// import { BenchmarkRunner } from "../../../utils/benchmarkTsSuite";
declare function print(arg:any) : string;
declare interface ArkTools{
	timeInUs(arg:any):number
}
// Modify n value to change the difficulty of the benchmark
// suggesting using input = 25000000;
const input: number = 250000;

class AminoAcid {
    prob: number = 0.0;
    sym: number = 0;
    constructor(prob: number, sym: number) {
        this.prob = prob;
        this.sym = sym;
    }
}

const IM = 139968;
const IA = 3877;
const IC = 29573;
const SEED = 42;

let n: number = input;
const width: number = 60;

const iub: AminoAcid[] = [
    new AminoAcid(0.27, 97), // "a"),
    new AminoAcid(0.12, 99), // "c"),
    new AminoAcid(0.12, 103), // "g"),
    new AminoAcid(0.27, 116), // "t"),
    new AminoAcid(0.02, 66), // "B"),
    new AminoAcid(0.02, 68), // "D"),
    new AminoAcid(0.02, 72), // "H"),
    new AminoAcid(0.02, 75), // "K"),
    new AminoAcid(0.02, 77), // "M"),
    new AminoAcid(0.02, 78), // "N"),
    new AminoAcid(0.02, 82), // "R"),
    new AminoAcid(0.02, 83), // "S"),
    new AminoAcid(0.02, 86), // "V"),
    new AminoAcid(0.02, 87), // "W"),
    new AminoAcid(0.02, 89), // "Y"),
];

function binarySearch(rnd: number, arr: AminoAcid[]): number {
    let low = 0;
    let high = arr.length - 1;
    for (; low <= high;) {
        let middle = (low + high) >>> 1;
        if (arr[middle].prob >= rnd) {
            high = middle - 1;
        } else {
            low = middle + 1;
        }
    }
    return arr[high + 1].sym;
}

function accumulateProbabilities(acid: AminoAcid[]): void {
    for (let i = 1; i < acid.length; i++) {
        acid[i].prob += acid[i-1].prob;
    }
}

function randomFasta(buffer: number[], acid: AminoAcid[], n: number) {
    let cnt = n;
    accumulateProbabilities(acid);
    let pos = 0;
    let seed = SEED;
    while (cnt > 0) {
        let m = cnt > width ? width : cnt;
        let f = 1.0 / IM;
        let myrand = seed;
        for (let i = 0; i < m; i++) {
            myrand = (myrand * IA + IC) % IM;
            let r = myrand * f;
            buffer[pos] = binarySearch(r, acid);
            pos++;
            if (pos === buffer.length) {
                pos = 0;
            }
        }
        seed = myrand;
        buffer[pos] = 10;
        pos++;
        if (pos === buffer.length) {
            pos = 0;
        }
        cnt -= m;
    }
}

export function RunFastaRandom2() {
    const bufferSize: number = 256 * 1024;
    let buffer = new Array();
    for (let i = 0; i < bufferSize; i++) {
        buffer.push(10);
    }
    const homosapiens: AminoAcid[] = [
        new AminoAcid(0.3029549426680, 97), // "a"),
        new AminoAcid(0.1979883004921, 99), // "c"),
        new AminoAcid(0.1975473066391, 103), // "g"),
        new AminoAcid(0.3015094502008, 116), // "t"),
    ];
    let start = ArkTools.timeInUs();
    randomFasta(buffer, homosapiens, 5*n);
    let end = ArkTools.timeInUs();
    let time = (end - start) / 1000
    print("Array Access - RunFastaRandom2:\t"+String(time)+"\tms");
	return time;
}
RunFastaRandom2()
// let runner3 = new BenchmarkRunner("Array Access - RunFastaRandom2", RunFastaRandom2);
// runner3.run();
